#pragma once

#include "my_defs.h"
#include "my_crc.h"
#include "my_str.h"
#include "my_rbtree.h"
#include "my_queue.h"
#include "my_log.h"

typedef struct {
    my_str_t                    key;
    void                        *data;
    int                         weight;
    my_queue_t                  queue;
} my_chash_node_t;

static inline void
my_chash_node_init(my_chash_node_t *node, my_str_t *key, void *data, int weight)
{
    assert(key != NULL);
    node->key = *key;
    node->data = data;
    node->weight = weight;
}

typedef struct {
    my_rbtree_node_t            tree_node;
    uint32_t                    crc_key;
    my_chash_node_t             *real_node;
} my_chash_vnode_t;

static inline void
my_chash_vnode_init(my_chash_vnode_t *vnode, my_chash_node_t *node, int idx)
{
    char suffix[64];
    int n = snprintf(suffix, 64, "%d-%d=%d$%d", idx, idx, idx, idx);

    uint32_t crc;
    my_crc32_init(crc);
    my_crc32_update(&crc, (const u_char *)node->key.data, (size_t)node->key.len);
    my_crc32_update(&crc, (const u_char *)suffix, (size_t)n);
    my_crc32_final(crc);

    vnode->crc_key = crc;
    vnode->real_node = node;
}

static inline int
my_chash_vnode_cmp(my_rbtree_node_t *a, my_rbtree_node_t *b)
{
    my_chash_vnode_t *anode = (my_chash_vnode_t *)a;
    my_chash_vnode_t *bnode = (my_chash_vnode_t *)b;

    if (anode->crc_key == bnode->crc_key) {
        return 0;
    }

    return anode->crc_key > bnode->crc_key ? 1 : -1;
}

typedef struct my_chash_s my_chash_t;

struct my_chash_s {
    int                 replace;
    int                 nnode;
    my_queue_t          head;
    my_rbtree_t         tree;
    my_rbtree_node_t    sentinel;
};

static inline void
my_chash_init(my_chash_t *chash, int replace) 
{
    if (replace < 1) {
        MY_LOG_FATAL("replace must gather than 0");
    }

    chash->replace = replace;
    chash->nnode = 0;
    my_queue_init(&chash->head);
    my_rbtree_init(&chash->tree, &chash->sentinel, my_chash_vnode_cmp);
}

void my_chash_add_node(my_chash_t *chash, my_str_t *key, void *data, int weight);

void my_chash_build(my_chash_t *chash);

typedef my_bool_t (*my_chash_node_check_pt) (my_chash_node_t *node);

void *my_chash_get(my_chash_t *chash, my_str_t *key, my_chash_node_check_pt checker);

void my_chash_release(my_chash_t *chash);